﻿/*
输入：
3 3
8 5 5
8 1 8
8 8 4
输出：
0 0
0 1
0 2
1 0
1 2
2 0
2 1
*/
// N行M列
string[] NMStrArr = Console.ReadLine().Split(" ");
int N = int.Parse(NMStrArr[0]);
int M = int.Parse(NMStrArr[1]);

// 地图
int[,] map = new int[N,M];
int[,] resMap = new int[N,M];
List<(int, int)> result = new List<(int, int)>();
for (int i = 0; i < N; i++)
{
    string[] line = Console.ReadLine().Split(" ");
    for (int j = 0; j < M; j++)
    {
        map[i, j] = int.Parse(line[j]);
    }
}

void dfs(int[,] map, int ki, int kj, int fill)
{
    // 找到一个结果
    if (resMap[ki, kj] != fill && resMap[ki, kj] != 0)
    {
        result.Add((ki, kj));
    }

    resMap[ki, kj] = fill;
    // 右侧流
    if (kj < M - 1 && map[ki, kj] <= map[ki, kj + 1] && resMap[ki, kj + 1] != fill)
    {
        dfs(map,ki,kj+1, fill);
    }
    // 下侧流
    if (ki < N - 1 && map[ki, kj] <= map[ki + 1, kj] && resMap[ki + 1, kj] != fill)
    {
        dfs(map,ki+1,kj, fill);
    }
    // 左侧流
    if (kj > 0 && map[ki, kj] <= map[ki, kj -1] && resMap[ki, kj - 1] != fill)
    {
        dfs(map,ki,kj-1, fill);
    }
    // 上侧流
    if (ki > 0 && map[ki, kj] <= map[ki-1, kj] && resMap[ki-1, kj] != fill)
    {
        dfs(map,ki-1,kj, fill);
    }

}
// 深度搜索，逆流而上 -- 第一组边界，填充1
for (int i = 0; i < N; i++)
{
    dfs(map, i, 0, 1);
}
for (int j = 0; j < M; j++)
{
    dfs(map, 0, j, 1);
}
// 深度搜索，逆流而上 -- 第二组边界， 填充2
for (int i = 0; i < N; i++)
{
    dfs(map, i, M-1, 2);
}
for (int j = 0; j < M; j++)
{
    dfs(map, N-1, j, 2);
}

for (int i = 0; i < result.Count; i++)
{
    (int r1, int r2) = result[i];
    Console.WriteLine($"{r1} {r2}");
}
